# box.py
"""This module provides the box class, which is a physical object that
is affected by local gravity, can be pushed by the player and can move
through portals.
"""
import Box2D.b2 as b2
import math
import pyglet

from camera import world_to_pixels, pixels_to_world
import config
from constants import APPLY_GRAVITY
from constants import STRENGTH_OF_GRAVITY as G
from debug import msg
import entity
import portalable
import resources

class BoxObject(entity.Dynamic):
    def __init__(self, mode, img, start_configuration, 
                 front_is_left=False,
                 portalable=None) :
        self.e_type = "box"

        super(BoxObject, self).__init__(mode, img, 
                                        start_configuration, 
                                        front_is_left=front_is_left, 
                                        portalable=portalable)

        self.fixture.friction = 0.15

        # Add a pendulum to indicate gravity-direction. Consists of a
        # body fixed to the box with a joint and a sprite.

        # Load image.
        img = resources.image("data/img/pendulum.png", (0.5,1))
        
        # Create body, centered on mass-center of box.
        (pos, vel, rot) = start_configuration

        self.pendulum_body = mode.world.CreateDynamicBody(
            position=self.body.worldCenter,
            angle=rot)

        self.pendulum_fixture = self.pendulum_body.CreatePolygonFixture(
            box=(pixels_to_world(img.width/2.0),
                 pixels_to_world(1.5),
                 (0, -pixels_to_world(14)), 
                 0),
            density = 1,
            userData = {"self":self})

        self.pendulum_fixture.sensor = True
        
        # Create a joint between the pendulum and the box.
        self.pendulum_joint = mode.world.CreateRevoluteJoint(
            bodyA = self.body,
            bodyB = self.pendulum_body,
            anchor = self.body.worldCenter,
            enableMotor = True,
            motorSpeed = 0.0,
            maxMotorTorque = 0.1)

        # Add image
        self.pendulum_sprite = pyglet.sprite.Sprite(
            img, batch=self.mode.batch_foreground)

        self.update_sprite()

    def update_sprite(self):
        """
        Extends function from entity.Dynamic to update
        pendulum_sprite.
        """
        super(BoxObject, self).update_sprite()
        
        try:
            self.pendulum_sprite.x = world_to_pixels(self.body.position[0])
            self.pendulum_sprite.y = world_to_pixels(self.body.position[1])

            # Pyglet sprites rotate clockwise
            self.pendulum_sprite.rotation = (-self.pendulum_body.angle) * (180 / math.pi)
        except AttributeError:
            pass

    def update(self, dt):
        """
        Extends function from entity.Dynamic to apply
        gravity to pendulum.
        """
        super(BoxObject, self).update(dt)

        if APPLY_GRAVITY:
            try:
                self.pendulum_body.ApplyForce(G * self.pendulum_body.mass * self.gravity_dir,
                                     self.pendulum_body.worldCenter)
            except AttributeError:
                pass

        self.pendulum_joint.motorSpeed = self.body.angularVelocity

        
class Box(portalable.Portalable):

    """A physical object that is affected by local gravity, can be
    pushed by the player and can move through portals.
    """

    def __init__(self, mode, start_configurations):
        self.image = resources.image("data/img/box.png", (0.5, 0.5))
        super(Box, self).__init__(mode, start_configurations,
                                  fixed_rotation=False, e_type="box")

    def add_instance(self, start_configuration, 
                     front_is_left=False):
        o = BoxObject(self.mode, self.image,
                      start_configuration, 
                      front_is_left=front_is_left,
                      portalable=self)
        self.objects.append(o)
        return o
